//
//  YNetworkRequest.m
//  YNetworking
//
//  Created by osnail on 2018/9/27.
//  Copyright © 2018 PH. All rights reserved.
//

#import "YNetworkRequest.h"
#import "AFNetworking.h"
#import <YYKit/YYKit.h>

NSString *const kYSNetManager_cache_key=@"kYSNetManager_cache_key";
NSString *const kYSNetManager_cache_response_key=@"kYSNetManager_cache_response_key";
NSString *const kLoginStatusTokenOverdueNotification = @"kLoginStatusTokenOverdueNotification";

@interface YNetworkRequest ()

@end

@implementation YNetworkRequest

- (instancetype)init {
    
    self = [super init];
    if (self) {
        
        self.requestSerializerJSON = YES;
        self.responseSerializerJSON = YES;
        self.requestHeaderField = @{};
        self.cacheMode = YNetworkRequest_cacheMode_noCache;
#if DEBUG
        self.timeoutTime = 20.0;
        self.showLog = YES;
#else
        self.timeoutTime = 30.0;
        self.showLog = NO;
#endif
    }
    return self;
}

- (NSURLSessionTask *)startRequestWithCompletion:(void (^)(id))completion failure:(void (^)(NSError *))failure {
    
    return [self requestTypeMethod:self.requestType url:[NSString stringWithFormat:@"%@/%@", self.baseURL, self.requestURL] parameters:self.requestParames headers:self.requestHeaderField cacheMode:self.cacheMode handler:^(id  _Nullable aResponseObject, NSError * _Nullable anError) {
        
        if (aResponseObject != nil && anError == nil && completion != nil) {
            [self requestCompletion:aResponseObject];
            completion(aResponseObject);
        } else if (anError != nil && failure != nil) {
            failure(anError);
        }
    }];
}

/// 请求结束 可以用来处理异常情况
- (void)requestCompletion:(id)responseObject {
    
}

- (NSURLSessionTask *)requestTypeMethod:(YRequestType)method
                                    url:(NSString *)url
                             parameters:(id)parameters
                                headers:(NSDictionary *)requestHeaderField
                                handler:(YHandlerBlock)handlerBlock
{
    return [self requestTypeMethod:method
                               url:url
                        parameters:parameters
                           headers:requestHeaderField
                         cacheMode:YNetworkRequest_cacheMode_noCache
                           handler:handlerBlock];
}

- (NSURLSessionTask *)requestTypeMethod:(YRequestType)method
                                    url:(NSString *)url
                             parameters:(id)parameters
                                headers:(NSDictionary *)requestHeaderField
                              cacheMode:(YNetworkRequest_cacheMode)cacheMode
                                handler:(YHandlerBlock)handlerBlock
{
    
    if (![NSURL URLWithString:url]) {
        NSLog(@"url is nil");
        return nil;
    }
    if (self.showLog) {
        NSArray *methodArr = @[@"GET",@"POST",@"PUT",@"PATCH",@"DELETE"];
        NSLog(@"\n\n请求类型===%@\n请求地址URL===%@\n请求参数===%@\n\n",
              methodArr[method],
              url,
              parameters);
    }
    
    [YNetworkHelper setRequestTimeoutInterval:self.timeoutTime];
    if (self.requestSerializerJSON) {
        [YNetworkHelper setRequestSerializer:YRequestSerializerJSON];
    } else {
        [YNetworkHelper setRequestSerializer:YRequestSerializerHTTP];
    }
    if (self.responseSerializerJSON) {
        [YNetworkHelper setResponseSerializer:YResponseSerializerJSON];
    } else {
        [YNetworkHelper setResponseSerializer:YResponseSerializerHTTP];
    }
    
    if (cacheMode == YNetworkRequest_cacheMode_cacheAndRequest) {
        
        [self getResponse:method
                      url:url
               parameters:parameters
                  headers:requestHeaderField
               onResponse:^(id response) {
            // 先读取到缓存，然后获取接口数据
            if(response) handlerBlock(response,nil);
        }];
    }
    NSURLSessionTask *requestTask = [YNetworkHelper requestTypeMethod:method url:url parameters:parameters header:requestHeaderField handler:^(id  _Nullable aResponseObject, NSError * _Nullable anError) {
        
        //写控制台日志
        [self writeLog:method
            parameters:parameters
                   url:url
       aResponseObject:aResponseObject];
        
        if (anError == nil && aResponseObject != nil) {
            // aResponseObject not dictionary
            if (![aResponseObject isKindOfClass:[NSDictionary class]]) {
                
                NSError *err = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorUnknown userInfo:@{NSLocalizedDescriptionKey:@"数据格式返回错误!"}];
                
                //需要缓存，优先从缓存中读取
                if(cacheMode==YNetworkRequest_cacheMode_onFail)
                {
                    [self getResponse:method
                                  url:url
                           parameters:parameters
                              headers:requestHeaderField
                           onResponse:^(id response){
                        //如果读取到缓存，就使用缓存数据
                        //如果没有读取到缓存，就仍然使用原有报文返回数据
                        if(response)
                            handlerBlock(response,nil);
                        else
                            handlerBlock(nil, err);
                    }];
                }
                else
                {
                    handlerBlock(nil, err);
                }
                return;
            } else {
                if ([[aResponseObject objectForKey:@"tokenStatus"] boolValue] == true ||
                    [[aResponseObject objectForKey:@"code"] integerValue] == 301) {
                    /// token过期
                    [[NSNotificationCenter defaultCenter] postNotificationName:kLoginStatusTokenOverdueNotification object:nil];
                }
                
                //需要缓存，就将响应数据存储起来
                if(cacheMode!=YNetworkRequest_cacheMode_noCache)
                {
                    [self saveResponse:method
                                   url:url
                            parameters:parameters
                               headers:requestHeaderField
                              response:aResponseObject];
                }
                
                handlerBlock(aResponseObject,anError);
            }
        } else {
            //需要缓存，优先从缓存中读取
            if(cacheMode==YNetworkRequest_cacheMode_onFail)
            {
                [self getResponse:method
                              url:url
                       parameters:parameters
                          headers:requestHeaderField
                       onResponse:^(id response){
                    //如果读取到缓存，就使用缓存数据
                    //如果没有读取到缓存，就仍然使用原有报文返回数据
                    if(response)
                        handlerBlock(response,nil);
                    else
                        handlerBlock(aResponseObject,anError);
                }];
            }
            else
            {
                handlerBlock(aResponseObject,anError);
            }
        }
    }];
    self.requestTask = requestTask;
    return requestTask;
}

/// 写控制台日志
/// @param method 请求方法
/// @param parameters 参数
/// @param url 请求地址
/// @param aResponseObject 响应地址
- (void)writeLog:(YRequestType)method
      parameters:(id)parameters
             url:(NSString *)url
 aResponseObject:(id)aResponseObject
{
    if (self.showLog) {
        
        NSArray *methodArr = @[@"GET",@"POST",@"PUT",@"PATCH",@"DELETE"];
        if (parameters) {
            if ([NSJSONSerialization isValidJSONObject:parameters]) {
                NSData* jsonData = [NSJSONSerialization dataWithJSONObject:parameters options:NSJSONWritingPrettyPrinted error:nil];
                NSString *jsonStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
                NSLog(@"parameter is: %@",jsonStr);
            }
        }
        if(aResponseObject)
        {
            NSData* jsonData = [NSJSONSerialization dataWithJSONObject:aResponseObject
                                                               options:NSJSONWritingPrettyPrinted
                                                                 error:nil];
            NSString *jsonStr = [[NSString alloc] initWithData:jsonData
                                                      encoding:NSUTF8StringEncoding];
            NSLog(@"\n\n请求类型===%@\n请求地址URL===%@\n请求参数===%@\n返回结果===%@",
                  methodArr[method],
                  url,
                  parameters,
                  jsonStr);
            NSLog(@"\n\naResponseObject is: %@",jsonStr);
        }
    }
}

#pragma mark 私有方法--缓存相关

/// 获取缓存对象
-(YYCache *) getCache
{
    static YYCache *cache;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        cache=[YYCache cacheWithName:kYSNetManager_cache_key];
    });
    return cache;
}

/// 根据请求的相关参数构造一个缓存的key
/// @param method 请求方法
/// @param url 请求链接
/// @param parameters 参数列表
/// @param requestHeaderField 请求头数据
-(NSString *) contructCacheKey:(YRequestType)method
                           url:(NSString *)url
                    parameters:(id)parameters
                       headers:(NSDictionary *)requestHeaderField
{
    NSMutableString *str=[NSMutableString string];
    [str appendFormat:@"%@_",kYSNetManager_cache_response_key];
    [str appendFormat:@"%lu_%@_",(unsigned long)method,url];
    if(parameters&&[parameters isKindOfClass:[NSDictionary class]])
    {
        NSString *jsonStr=[parameters modelToJSONString];
        [str appendFormat:@"%@",jsonStr];
    }
    
    /*
     暂时不将header里面的数据作为存取缓存的关键信息
     头部通常含有时间戳数据，除非能把时间戳过滤出来，否则缓存无意义
     */
    
    //    if(requestHeaderField&&[requestHeaderField isKindOfClass:[NSDictionary class]])
    //    {
    //        NSString *jsonStr=[requestHeaderField modelToJSONString];
    //        [str appendFormat:@"%@",jsonStr];
    //    }
    
    return str;
}
/// 将相应数据存入缓存
/// @param response 响应数据
-(void) saveResponse:(YRequestType)method
                 url:(NSString *)url
          parameters:(id)parameters
             headers:(NSDictionary *)requestHeaderField
            response:(id)response
{
    NSString *key=[self contructCacheKey:method
                                     url:url
                              parameters:parameters
                                 headers:requestHeaderField];
    [[self getCache] setObject:response forKey:key withBlock:^{
        
    }];
}
/// 从缓存中读取数据
/// @param onResponse 响应数据
-(void) getResponse:(YRequestType)method
                url:(NSString *)url
         parameters:(id)parameters
            headers:(NSDictionary *)requestHeaderField
         onResponse:(void(^)(id response))onResponse
{
    NSString *key=[self contructCacheKey:method
                                     url:url
                              parameters:parameters
                                 headers:requestHeaderField];
    if([[self getCache] containsObjectForKey:key])
    {
        [[self getCache] objectForKey:key withBlock:^(NSString * _Nonnull key, id<NSCoding>  _Nonnull object) {
            dispatch_async(dispatch_get_main_queue(), ^{
                if(onResponse)
                    onResponse(object);
            });
        }];
    }
    else
    {
        if(onResponse)
            onResponse(nil);
    }
}

- (void)cancleTask {
    
    if (self && self.requestTask && [self isExecuting]) {
        [self.requestTask cancel];
    }
}

- (BOOL)isCancelled {
    
    if (!self.requestTask) {
        return NO;
    }
    return self.requestTask.state == NSURLSessionTaskStateCanceling;
}

- (BOOL)isExecuting {
    
    if (!self.requestTask) {
        return NO;
    }
    return self.requestTask.state == NSURLSessionTaskStateRunning;
}

@end
